#!/usr/bin/env ruby
# VotD - Verse of the Day
# Send daily verses messages with mailchimp and twilio
#
# Copyright 2015 Chris Jackson <chris@faithhack.com>
#
# This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

require 'rubygems'
require './config'
require 'bundler/setup'
Bundler.require(:default)
#require 'twilio-ruby'
#require 'google_drive'
#require 'esv_api'
#require 'mailchimp'

# set to false for testing
@send_sms = true
@send_mailchimp = true

# returns worksheet handle
def get_worksheet_from_gdrive(ss_title, ws_title)
  client = Google::APIClient.new(:application_name => '40DaysSMS',
  :application_version => '0.0.1')
  auth = client.authorization
  auth.client_id = Config::GDRIVE[:oauth_client_id]
  auth.client_secret = Config::GDRIVE[:oauth_client_secret]
  scope =  Config::GDRIVE[:scope]
  
  auth.redirect_uri = "http://localhost/redirect"
  auth.refresh_token = Config::GDRIVE[:oauth_refresh_token]
  auth.fetch_access_token!
  session = GoogleDrive.login_with_oauth(auth.access_token)
  
  session.file_by_title(ss_title).worksheet_by_title(ws_title)
end

def get_sms_recipients
  ws = get_worksheet_from_gdrive(Config::GDRIVE[:ss_title], Config::GDRIVE[:recipients_ws])
  ws.rows.collect{|r| r[2].to_i}.reject{|r| r == 0}
end

# ws: spreadsheet from google
# returns array of hashes of titles and rows froms schedule spreadsheet
def get_scheduled_messages
  ws = get_worksheet_from_gdrive(Config::GDRIVE[:ss_title], Config::GDRIVE[:schedule_ws])

  keys = ws.rows[0]
  messages_list = ws.rows.select {|r| r[0] == Time.now.strftime('%-m/%-d/%Y')} # get today's row(s)
  messages = []
  messages_list.each { |message| messages << Hash[*keys.zip(message).flatten] }
  messages.map! do |message|
    message.each do |k,v| 
      #find {ESV:.*}, {ESVF:.*}, and {.*} templates in message content and replace them
      v.gsub!(/\{ESV:(.*?)\}/) { |s| s = get_esv_text($1) }
      v.gsub!(/\{ESVF:(.*?)\}/) { |s| s = get_esv_text($1, true) }
      v.gsub!(/\{(.*?)\}/) { |s| s = message[$1] }
      message[k] = v
    end
    message
  end
  messages
end

def get_esv_text(verse, formated = false)
  output_format = ( formated ? "html" : "plain-text" )
  include_subheaders = ( formated ? true : false )
  include_passage_horizontal_lines = ( formated ? true : false )
  include_heading_horizontal_lines = ( formated ? true : false )
  include_heading_horizontal_lines = ( formated ? true : false )
  include_headings = ( formated ? true : false )

  # puts "ESV: getting #{verse}"
  bible = ESV::Client.new(:api_key => Config::ESV[:api_key])
  passage = bible.passage_query(verse, {'output-format' =>output_format,
                              'include-subheadings' => include_subheaders,
                              'include-passage-horizontal-lines' => include_passage_horizontal_lines,
                              'include-heading-horizontal-lines' => include_heading_horizontal_lines,
                              'include-headings' => include_headings,
                              'include-short-copyright' => false,
                              'include-verse-numbers' => false,
                              'include-footnotes' => false,
                              'line-length' => 0,
                              'include-passage-references' => false}).parsed_response.squeeze(" ").strip
   # puts "ESV: returned #{passage}"
   return passage unless passage.start_with?("ERROR")
   return "ESV API ERROR"
end


# message: hash of titles and row from schedule spreadsheet
# returns message string
def sms_message(message)
    msg_text = message['title'] != 0 ? "#{message['title'].chomp}: " : ""
    msg_text = message['verse'] != 0 ? "#{msg_text}#{message['verse']}: #{message['verse_text']}" : ""
    msg_text = message['additional_message'] != 0 ? "#{msg_text}\n#{message['additional_message'].chomp}" : ""
end

# split string to length preserving words
def split_into_chunks_by_size(chunk_size, string)
  string_split_into_chunks = [""]
  string.split(" ").each do |word|
    if (string_split_into_chunks[-1].length + 1 + word.length > chunk_size)
      string_split_into_chunks << word
    else
      string_split_into_chunks[-1] << " " + word
    end
  end
  string_split_into_chunks
end

# returns array of texts sized for sms (160 chars)
# split sms messages to right length and add "XofX" as needed
def prep_sms_message(message)
  message_parts = []

  if message.length > 160
    message_parts = split_into_chunks_by_size(153, message)
  else
    message_parts[0] = message
  end

  if message_parts.length > 1
    message_parts.each_index do | x |
      message_parts[x] = message_parts[x] + " (#{x + 1}of#{message_parts.length})"
    end
  end
  message_parts
end

def send_mailchimp_campaign
  #get the spreadsheet data
  message = get_scheduled_messages()[0]

  #get formated ESV text
  # message['esv_verse_formatted'] = get_esv_text(message['verse'], true)

  mailchimp = Mailchimp::API.new(Config::MAILCHIMP[:api_key])

  # get template
  template_id = mailchimp.campaigns.list({:title => Config::MAILCHIMP[:template_name]})['data'][0]['id']

  # clone the template and create a campaign
  campaign_id = mailchimp.campaigns.replicate(template_id)['id']
  mailchimp.campaigns.update(campaign_id,'options',{'title'=>message['title']})
  mailchimp.campaigns.update(campaign_id,'options',{'subject'=>message['title']})

  #get the content and loop through it
  content = mailchimp.campaigns.template_content(campaign_id)
  content.each do |k,v|
		if(v.is_a?(String))
			 v.gsub!(/\{(.*?)\}/) { |s| s = message[$1] }
      mailchimp.campaigns.update(campaign_id, 'content', {'sections' => {k => v}})
		end
  end
  if @send_mailchimp
    mailchimp.campaigns.send(campaign_id)
  end
  puts "SENDING MAILCHIMP: #{message['title']}"
end

# set up a client to talk to the Twilio REST API
def send_sms_messages(messages, numbers)
  client = Twilio::REST::Client.new(Config::TWILIO[:account_sid], Config::TWILIO[:auth_token])
  messages.each do | message |
    message_parts = prep_sms_message(sms_message(message))
    numbers.each do | number |
      message_parts.each do |part|
        # sleep 1.5
        if @send_sms
          message = client.account.messages.create(
            :from => Config::TWILIO[:from_number],
            :to => "+1" + number.to_s,
            :body => part
          )
        end
        puts "SENDING SMS: #{number.to_s}| #{part}"
      end
    end
  end
end

# main

unless ARGV.length == 0
  puts "Usage: ruby sendsms.rb\n"
  puts "configure access to google docs, twillio, and mailchimp in script"
  exit
end

numbers = get_sms_recipients
puts "get_numbers: #{numbers.length}"

messages = get_scheduled_messages
puts "get_messages: #{messages.length}"

send_mailchimp_campaign
puts "send_mailchimp_message complete"

send_sms_messages(messages, numbers)
puts "send_sms_messages complete"
